<template>
  <div class="custom-node">
    <!-- 输入连接桩 -->
    <template v-if="nodeType === 'input' || nodeType === 'all'">
      <div
        v-for="n in inputPortNum"
        :key="'input-' + n"
        class="port port-input"
        :data-port-id="'input-' + n"
        magnet="true"
        :style="{ '--total-ports': inputPortNum, '--n-index': n }"
      >
        <span class="port-label">{{ n }}</span>
      </div>
    </template>

    <!-- 输出连接桩 -->
    <template v-if="nodeType === 'output' || nodeType === 'all'">
      <div class="port port-output" data-port-id="output-1" magnet="true"></div>
    </template>

    <div class="title">
      <div class="text">
        <i :class="icon"></i><span style="margin-left: 5px">{{ text }}</span>
      </div>
    </div>

    <div class="body">
      <el-button type="text" @click="runCode(1)">运行</el-button>
      <el-button type="text" @click="runCode(2)">运行至所选</el-button>
    </div>

    <div class="bottom">
      <div class="btns">
        <el-button type="text" @click="runCode(1)">运行</el-button>
        <el-button type="text" @click="runCode(2)">运行至所选</el-button>
        <i class="el-icon-loading" style="size: 16px; color: #00c782"></i>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "CustomNode",
  inject: ["getNode"],
  data() {
    return {
      text: "自定义节点",
      id: "",
      icon: "",
      nodeType: "",
      inputPortNum: 0,
      connectedPorts: {}, // 记录已连接的端口 {input: {1: true, 2: false}, output: {1: true}}
      runningEdges: [], // 记录正在运行的边
    };
  },
  mounted() {
    const node = this.getNode();
    const nodeData = node.getData();
    this.id = nodeData.id;
    this.text = nodeData.label;
    this.icon = nodeData.value;
    this.nodeType = nodeData.id; // 节点类型存储在id字段中
    this.inputPortNum = nodeData.inputNum || 0;

    // 初始化连接桩状态
    this.initPortsState();

    // 监听连接变化
    const graph = node.model;
    if (graph) {
      graph.on("edge:connected", ({ edge }) => {
        this.updatePortConnections();
      });

      graph.on("edge:removed", () => {
        this.updatePortConnections();
      });

      // 监听鼠标进入连接桩事件，提高用户体验
      this.$el.querySelectorAll(".port").forEach((port) => {
        port.addEventListener("mouseenter", () => {
          port.style.transform = "scale(1.2)";
        });
        port.addEventListener("mouseleave", () => {
          port.style.transform = "scale(1)";
        });
      });
    }

    node.on("change:data", ({ current }) => {
      const { progress } = current;
      console.log("progress", progress);
      console.log("current", current);
    });
  },
  methods: {
    // 初始化连接桩状态
    initPortsState() {
      this.connectedPorts = {
        input: {},
        output: {},
      };

      // 初始化输入连接桩状态
      if (this.nodeType === "input" || this.nodeType === "all") {
        for (let i = 1; i <= this.inputPortNum; i++) {
          this.connectedPorts.input[i] = false;
        }
      }

      // 初始化输出连接桩状态
      if (this.nodeType === "output" || this.nodeType === "all") {
        this.connectedPorts.output[1] = false;
      }

      // 更新连接状态
      this.updatePortConnections();
    },

    // 检查端口是否已连接
    isPortConnected(portType, portIndex) {
      return (
        this.connectedPorts[portType] &&
        this.connectedPorts[portType][portIndex]
      );
    },

    // 更新连接桩连接状态
    updatePortConnections() {
      const node = this.getNode();
      const graph = node.model;

      // 重置连接状态
      if (this.nodeType === "input" || this.nodeType === "all") {
        for (let i = 1; i <= this.inputPortNum; i++) {
          this.connectedPorts.input[i] = false;
        }
      }

      if (this.nodeType === "output" || this.nodeType === "all") {
        this.connectedPorts.output[1] = false;
      }

      if (graph) {
        // 获取与当前节点相连的所有边
        const edges = graph.getConnectedEdges(node);

        edges.forEach((edge) => {
          const { source, target } = edge;

          // 如果当前节点是源节点（输出端）
          if (source.cell === node.id) {
            const portId = source.port;
            if (portId) {
              const portIndex = parseInt(portId.split("-")[1]);
              this.connectedPorts.output[portIndex] = true;
            }
          }

          // 如果当前节点是目标节点（输入端）
          if (target.cell === node.id) {
            const portId = target.port;
            if (portId) {
              const portIndex = parseInt(portId.split("-")[1]);
              this.connectedPorts.input[portIndex] = true;
            }
          }
        });
      }
    },

    // 运行代码
    // 递归获取所有上游边
    getUpstreamEdges(node, visited = new Set()) {
      const graph = node.model;
      const edges = new Set();

      if (graph && !visited.has(node.id)) {
        visited.add(node.id);
        graph.getPredecessors(node).forEach((predecessor) => {
          const connEdges = graph.getConnectedEdges(predecessor, {
            outgoing: true,
            incoming: false,
          });
          connEdges.forEach((edge) => edges.add(edge));
          this.getUpstreamEdges(predecessor, visited).forEach((e) =>
            edges.add(e)
          );
        });
      }
      return Array.from(edges);
    },

    runCode(type) {
      const node = this.getNode();
      const graph = node.model;

      if (graph) {
        let edges = [];
        if (type === 1) {
          // 获取所有直接连接边
          edges = graph.getConnectedEdges(node);
        } else if (type === 2) {
          // 获取所有上游边链
          edges = this.getUpstreamEdges(node);
        }

        // 设置边动画
        edges.forEach((edge) => {
          edge.attr("line/strokeDasharray", 5);
          edge.attr("line/style/animation", "ant-line 30s infinite linear");
          this.runningEdges.push(edge.id);
        });

        // 恢复样式逻辑保持不变
        setTimeout(() => {
          edges.forEach((edge) => {
            edge.attr("line/strokeDasharray", 0);
            edge.attr("line/style/animation", "none");
            const index = this.runningEdges.indexOf(edge.id);
            if (index > -1) this.runningEdges.splice(index, 1);
          });
        }, 3000);
      }
    },
  },
};
</script>

<style>
/* 边动画效果 */
@keyframes ant-line {
  to {
    stroke-dashoffset: -1000;
  }
}
</style>
<style lang="less" scoped>
.custom-node {
  width: 100%;
  height: 100%;
  border-radius: 6px;
  border: 1px solid #2d8bff;
  position: relative;

  /* 连接桩样式 */
  .port {
    position: absolute;
    width: 13px;
    height: 13px;
    border-radius: 50%;
    background-color: #5f95ff;
    box-sizing: border-box;
    cursor: crosshair;
    z-index: 9999;
    transition: all 0.3s;

    &:hover {
      transform: scale(1.2);
    }

    /* 连接桩标签 */
    .port-label {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 10px;
      color: #333;
      pointer-events: none;
    }
  }

  /* 输入连接桩 - 垂直居中排列 */
  .port-input {
    left: -8px;
    /* 使用calc计算每个连接桩的位置，实现垂直居中均匀分布 */
    /* 通用公式：top = 50% + (index - (total + 1)/2) * gap */
    /* index从1开始，total是总数，gap是间距 */
    /* 使用CSS变量计算每个连接桩的位置 */
    --port-gap: 30px; /* 连接桩之间的间距，更紧凑的布局 */
    top: calc(
      50% + (var(--n-index, 1) - (var(--total-ports, 1) + 1) / 2) *
        var(--port-gap)
    );
  }

  /* 输出连接桩 */
  .port-output {
    right: -8px;
    top: 50%;
  }

  .title {
    height: 55px;
    font-size: 14px;
    padding: 0 10px;
    border-radius: 6px 6px 0 0;
    box-sizing: border-box;
    background: linear-gradient(to bottom, #e1efff, #fff);
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .body {
    padding: 10px;
    box-sizing: border-box;
    background-color: #fff;
    height: calc(100% - 96px);
    border-radius: 0 0 6px 6px;
  }
  .bottom {
    height: 40px;
    border-top: 1px solid #e4e7ed;
    background-color: #fff;
    border-radius: 0 0 6px 6px;
    display: flex;
    justify-content: flex-end;
    .btns {
      width: 70%;
      padding: 0 10px;
      box-sizing: border-box;
      display: flex;
      justify-content: space-around;
      align-items: center;
    }
  }
}
</style>
